package it.polito.connectedcar.network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;


/**
 * This class deals with low level network communication.
 * It receives Message , convert it in UDP datagram and sends it to the given destination.
 * The message will contain an authenticator to be used to calculate the HMAC-SHA256 digest to be appended to the datagram
 * 
 * 
 * @author nicola
 *
 */
public class NetworkConnectionManager {
	
	
	private MessageReceiver messageReceiveListener;
	private DatagramSocket socket;
	private int listeningPort;
	private Thread socketReaderThread;
	public NetworkConnectionManager(int port) {
		
		listeningPort=port;
	}
	
	
	public void init() throws SocketException{
		socket = new DatagramSocket(listeningPort);
		socketReaderThread = new Thread(new SocketReader());
		socketReaderThread.start();
	}
	
	private void onReceiveDatagram(DatagramPacket packet){
		SocketAddress sa = packet.getSocketAddress();
		/*1) verify integrity and authentication of peer( check the DIGEST ) 
		 *2) verify is not a reply ( reply attack )-> verify the timestamp anc check against the last arrived datagram from the specified peer.
		 *In order to do this , we need a map with each sender address and the last timestamp ( like Kerberos )
		 *
		 *3) 
		 *TODO : check address and port , verify is not the TCC .
		 *If address does not correspond to TCC and it is not in the neighborhood,decide what to do
		 *If address corresponds to TCC , check content 
		 *
		 *Extract the Datagram and create a Message
		 *
		 */
		
		
		
		int targetEntity = packet.getData()[0];
		EntityType type = EntityType.fromEntityCode(targetEntity);
		Message m = null;
		switch(type)
		{
		case INDUCTIVE_LOOP:
			break;
		case TRAFFIC_LIGHT:
			break;
		case VEHICLE:
			m = new VehicleMessage(packet.getData());
			break;
		default:
			break;
		}
		if(messageReceiveListener!=null)
			messageReceiveListener.onReceive(m);
		else
			m.destroy();
	}
	
	public void sendMessage(Message message,InetAddress target,int port) throws IOException{
		socket.send(new DatagramPacket(message.getMessageAsBytes(), message.getMessageAsBytes().length, new InetSocketAddress(target, port)));
	}
	
	public void setMessageReceiveListsner(MessageReceiver messageReceiveListener)
	{
		this.messageReceiveListener = messageReceiveListener;
	}
	
	public MessageReceiver getMessagereReceiveListener()
	{
		return this.messageReceiveListener;
	}
	
	private class SocketReader implements Runnable
	{

		@Override
		public void run() {
			DatagramPacket dp = null;
			while(!socket.isClosed())
			{
				try {
					socket.receive(dp);
					onReceiveDatagram(dp);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
}
